home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / ftp / new / cmds.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-10-27  |  38.3 KB  |  2,173 lines

  1. /*
  2.  * Copyright (c) 1985, 1989 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. #ifndef lint
  19. static char sccsid[] = "@(#)cmds.c    5.16 (Berkeley) 3/21/89";
  20. #endif /* not lint */
  21.  
  22. /*
  23.  * FTP User Program -- Command Routines.
  24.  */
  25. #include <sys/param.h>
  26. #include <sys/wait.h>
  27. #include <sys/stat.h>
  28. #include <sys/socket.h>
  29.  
  30. #include <arpa/ftp.h>
  31.  
  32. #include <signal.h>
  33. #include <stdio.h>
  34. #include <errno.h>
  35. #include <netdb.h>
  36. #include <ctype.h>
  37. #include <time.h>
  38.  
  39. #include "ftp_var.h"
  40.  
  41.  
  42. extern    char *globerr;
  43. extern    char **glob();
  44. extern    char *home;
  45. extern    char *remglob();
  46. extern    char *getenv();
  47. extern    char *index();
  48. extern    char *rindex();
  49. extern off_t restart_point;
  50. extern char reply_string[];
  51.  
  52. char *mname;
  53. jmp_buf jabort;
  54. char *dotrans(), *domap();
  55.  
  56. /*
  57.  * Connect to peer server and
  58.  * auto-login, if possible.
  59.  */
  60. setpeer(argc, argv)
  61.     int argc;
  62.     char *argv[];
  63. {
  64.     char *host, *hookup();
  65.     int port;
  66.  
  67.     if (connected) {
  68.         printf("Already connected to %s, use close first.\n",
  69.             hostname);
  70.         code = -1;
  71.         return;
  72.     }
  73.     if (argc < 2) {
  74.         (void) strcat(line, " ");
  75.         printf("(to) ");
  76.         (void) gets(&line[strlen(line)]);
  77.         makeargv();
  78.         argc = margc;
  79.         argv = margv;
  80.     }
  81.     if (argc > 3) {
  82.         printf("usage: %s host-name [port]\n", argv[0]);
  83.         code = -1;
  84.         return;
  85.     }
  86.     port = sp->s_port;
  87.     if (argc > 2) {
  88.         port = atoi(argv[2]);
  89.         if (port <= 0) {
  90.             printf("%s: bad port number-- %s\n", argv[1], argv[2]);
  91.             printf ("usage: %s host-name [port]\n", argv[0]);
  92.             code = -1;
  93.             return;
  94.         }
  95.         port = htons(port);
  96.     }
  97.     host = hookup(argv[1], port);
  98.     if (host) {
  99.         connected = 1;
  100.         if (autologin) {
  101.             int overbose;
  102.  
  103.             (void) login(argv[1]);
  104. #if defined(unix) && NBBY == 8
  105. /*
  106.  * this ifdef is to keep someone form "porting" this to an incompatible
  107.  * system and not checking this out. This way they have to think about it.
  108.  */
  109.             overbose = verbose;
  110.             if (debug == 0)
  111.                 verbose = -1;
  112.             if (command("SYST") == COMPLETE && overbose) {
  113.                 register char *cp, c;
  114.                 cp = index(reply_string+4, ' ');
  115.                 if (cp == NULL)
  116.                     cp = index(reply_string+4, '\r');
  117.                 if (cp) {
  118.                     if (cp[-1] == '.')
  119.                         cp--;
  120.                     c = *cp;
  121.                     *cp = '\0';
  122.                 }
  123.  
  124.                 printf("Remote system type is %s.\n",
  125.                     reply_string+4);
  126.                 if (cp)
  127.                     *cp = c;
  128.             }
  129.             if (!strncmp(reply_string, "215 UNIX Type: L8", 17)) {
  130.                 setbinary();
  131.                 if (overbose)
  132.                     printf("Using %s mode to transfer files.\n",
  133.                     typename);
  134.             } else if (overbose && 
  135.                 !strncmp(reply_string, "215 TOPS20", 10)) {
  136.                 printf(
  137. "Remember to set tenex mode when transfering binary files from this machine.\n");
  138.             }
  139.             verbose = overbose;
  140. #endif /* unix */
  141.         }
  142.     }
  143. }
  144.  
  145. struct    types {
  146.     char    *t_name;
  147.     char    *t_mode;
  148.     int    t_type;
  149.     char    *t_arg;
  150. } types[] = {
  151.     { "ascii",    "A",    TYPE_A,    0 },
  152.     { "binary",    "I",    TYPE_I,    0 },
  153.     { "image",    "I",    TYPE_I,    0 },
  154.     { "ebcdic",    "E",    TYPE_E,    0 },
  155.     { "tenex",    "L",    TYPE_L,    bytename },
  156.     0
  157. };
  158.  
  159. /*
  160.  * Set transfer type.
  161.  */
  162. settype(argc, argv)
  163.     char *argv[];
  164. {
  165.     register struct types *p;
  166.     int comret;
  167.  
  168.     if (argc > 2) {
  169.         char *sep;
  170.  
  171.         printf("usage: %s [", argv[0]);
  172.         sep = " ";
  173.         for (p = types; p->t_name; p++) {
  174.             printf("%s%s", sep, p->t_name);
  175.             if (*sep == ' ')
  176.                 sep = " | ";
  177.         }
  178.         printf(" ]\n");
  179.         code = -1;
  180.         return;
  181.     }
  182.     if (argc < 2) {
  183.         printf("Using %s mode to transfer files.\n", typename);
  184.         code = 0;
  185.         return;
  186.     }
  187.     for (p = types; p->t_name; p++)
  188.         if (strcmp(argv[1], p->t_name) == 0)
  189.             break;
  190.     if (p->t_name == 0) {
  191.         printf("%s: unknown mode\n", argv[1]);
  192.         code = -1;
  193.         return;
  194.     }
  195.     if ((p->t_arg != NULL) && (*(p->t_arg) != '\0'))
  196.         comret = command ("TYPE %s %s", p->t_mode, p->t_arg);
  197.     else
  198.         comret = command("TYPE %s", p->t_mode);
  199.     if (comret == COMPLETE) {
  200.         (void) strcpy(typename, p->t_name);
  201.         type = p->t_type;
  202.     }
  203. }
  204.  
  205. /*
  206.  * Set binary transfer type.
  207.  */
  208. /*VARARGS*/
  209. setbinary()
  210. {
  211.  
  212.     call(settype, "type", "binary", 0);
  213. }
  214.  
  215. /*
  216.  * Set ascii transfer type.
  217.  */
  218. /*VARARGS*/
  219. setascii()
  220. {
  221.  
  222.     call(settype, "type", "ascii", 0);
  223. }
  224.  
  225. /*
  226.  * Set tenex transfer type.
  227.  */
  228. /*VARARGS*/
  229. settenex()
  230. {
  231.  
  232.     call(settype, "type", "tenex", 0);
  233. }
  234.  
  235. /*
  236.  * Set ebcdic transfer type.
  237.  */
  238. /*VARARGS*/
  239. setebcdic()
  240. {
  241.  
  242.     call(settype, "type", "ebcdic", 0);
  243. }
  244.  
  245. /*
  246.  * Set file transfer mode.
  247.  */
  248. /*ARGSUSED*/
  249. setmode(argc, argv)
  250.     char *argv[];
  251. {
  252.  
  253.     printf("We only support %s mode, sorry.\n", modename);
  254.     code = -1;
  255. }
  256.  
  257. /*
  258.  * Set file transfer format.
  259.  */
  260. /*ARGSUSED*/
  261. setform(argc, argv)
  262.     char *argv[];
  263. {
  264.  
  265.     printf("We only support %s format, sorry.\n", formname);
  266.     code = -1;
  267. }
  268.  
  269. /*
  270.  * Set file transfer structure.
  271.  */
  272. /*ARGSUSED*/
  273. setstruct(argc, argv)
  274.     char *argv[];
  275. {
  276.  
  277.     printf("We only support %s structure, sorry.\n", structname);
  278.     code = -1;
  279. }
  280.  
  281. /*
  282.  * Send a single file.
  283.  */
  284. put(argc, argv)
  285.     int argc;
  286.     char *argv[];
  287. {
  288.     char *cmd;
  289.     int loc = 0;
  290.     char *oldargv1, *oldargv2;
  291.  
  292.     if (argc == 2) {
  293.         argc++;
  294.         argv[2] = argv[1];
  295.         loc++;
  296.     }
  297.     if (argc < 2) {
  298.         (void) strcat(line, " ");
  299.         printf("(local-file) ");
  300.         (void) gets(&line[strlen(line)]);
  301.         makeargv();
  302.         argc = margc;
  303.         argv = margv;
  304.     }
  305.     if (argc < 2) {
  306. usage:
  307.         printf("usage:%s local-file remote-file\n", argv[0]);
  308.         code = -1;
  309.         return;
  310.     }
  311.     if (argc < 3) {
  312.         (void) strcat(line, " ");
  313.         printf("(remote-file) ");
  314.         (void) gets(&line[strlen(line)]);
  315.         makeargv();
  316.         argc = margc;
  317.         argv = margv;
  318.     }
  319.     if (argc < 3) 
  320.         goto usage;
  321.     oldargv1 = argv[1];
  322.     oldargv2 = argv[2];
  323.     if (!globulize(&argv[1])) {
  324.         code = -1;
  325.         return;
  326.     }
  327.     /*
  328.      * If "globulize" modifies argv[1], and argv[2] is a copy of
  329.      * the old argv[1], make it a copy of the new argv[1].
  330.      */
  331.     if (argv[1] != oldargv1 && argv[2] == oldargv1) {
  332.         argv[2] = argv[1];
  333.     }
  334.     cmd = (argv[0][0] == 'a') ? "APPE" : ((sunique) ? "STOU" : "STOR");
  335.     if (loc && ntflag) {
  336.         argv[2] = dotrans(argv[2]);
  337.     }
  338.     if (loc && mapflag) {
  339.         argv[2] = domap(argv[2]);
  340.     }
  341.     sendrequest(cmd, argv[1], argv[2],
  342.         argv[1] != oldargv1 || argv[2] != oldargv2);
  343. }
  344.  
  345. /*
  346.  * Send multiple files.
  347.  */
  348. mput(argc, argv)
  349.     char *argv[];
  350. {
  351.     register int i;
  352.     int ointer, (*oldintr)(), mabort();
  353.     extern jmp_buf jabort;
  354.     char *tp;
  355.  
  356.     if (argc < 2) {
  357.         (void) strcat(line, " ");
  358.         printf("(local-files) ");
  359.         (void) gets(&line[strlen(line)]);
  360.         makeargv();
  361.         argc = margc;
  362.         argv = margv;
  363.     }
  364.     if (argc < 2) {
  365.         printf("usage:%s local-files\n", argv[0]);
  366.         code = -1;
  367.         return;
  368.     }
  369.     mname = argv[0];
  370.     mflag = 1;
  371.     oldintr = signal(SIGINT, mabort);
  372.     (void) setjmp(jabort);
  373.     if (proxy) {
  374.         char *cp, *tp2, tmpbuf[MAXPATHLEN];
  375.  
  376.         while ((cp = remglob(argv,0)) != NULL) {
  377.             if (*cp == 0) {
  378.                 mflag = 0;
  379.                 continue;
  380.             }
  381.             if (mflag && confirm(argv[0], cp)) {
  382.                 tp = cp;
  383.                 if (mcase) {
  384.                     while (*tp && !islower(*tp)) {
  385.                         tp++;
  386.                     }
  387.                     if (!*tp) {
  388.                         tp = cp;
  389.                         tp2 = tmpbuf;
  390.                         while ((*tp2 = *tp) != NULL) {
  391.                              if (isupper(*tp2)) {
  392.                                 *tp2 = 'a' + *tp2 - 'A';
  393.                              }
  394.                              tp++;
  395.                              tp2++;
  396.                         }
  397.                     }
  398.                     tp = tmpbuf;
  399.                 }
  400.                 if (ntflag) {
  401.                     tp = dotrans(tp);
  402.                 }
  403.                 if (mapflag) {
  404.                     tp = domap(tp);
  405.                 }
  406.                 sendrequest((sunique) ? "STOU" : "STOR",
  407.                     cp, tp, cp != tp || !interactive);
  408.                 if (!mflag && fromatty) {
  409.                     ointer = interactive;
  410.                     interactive = 1;
  411.                     if (confirm("Continue with","mput")) {
  412.                         mflag++;
  413.                     }
  414.                     interactive = ointer;
  415.                 }
  416.             }
  417.         }
  418.         (void) signal(SIGINT, oldintr);
  419.         mflag = 0;
  420.         return;
  421.     }
  422.     for (i = 1; i < argc; i++) {
  423.         register char **cpp, **gargs;
  424.  
  425.         if (!doglob) {
  426.             if (mflag && confirm(argv[0], argv[i])) {
  427.                 tp = (ntflag) ? dotrans(argv[i]) : argv[i];
  428.                 tp = (mapflag) ? domap(tp) : tp;
  429.                 sendrequest((sunique) ? "STOU" : "STOR",
  430.                     argv[i], tp, tp != argv[i] || !interactive);
  431.                 if (!mflag && fromatty) {
  432.                     ointer = interactive;
  433.                     interactive = 1;
  434.                     if (confirm("Continue with","mput")) {
  435.                         mflag++;
  436.                     }
  437.                     interactive = ointer;
  438.                 }
  439.             }
  440.             continue;
  441.         }
  442.         gargs = glob(argv[i]);
  443.         if (globerr != NULL) {
  444.             printf("%s\n", globerr);
  445.             if (gargs) {
  446.                 blkfree(gargs);
  447.                 free(gargs);
  448.             }
  449.             continue;
  450.         }
  451.         for (cpp = gargs; cpp && *cpp != NULL; cpp++) {
  452.             if (mflag && confirm(argv[0], *cpp)) {
  453.                 tp = (ntflag) ? dotrans(*cpp) : *cpp;
  454.                 tp = (mapflag) ? domap(tp) : tp;
  455.                 sendrequest((sunique) ? "STOU" : "STOR",
  456.                     *cpp, tp, *cpp != tp || !interactive);
  457.                 if (!mflag && fromatty) {
  458.                     ointer = interactive;
  459.                     interactive = 1;
  460.                     if (confirm("Continue with","mput")) {
  461.                         mflag++;
  462.                     }
  463.                     interactive = ointer;
  464.                 }
  465.             }
  466.         }
  467.         if (gargs != NULL) {
  468.             blkfree(gargs);
  469.             free(gargs);
  470.         }
  471.     }
  472.     (void) signal(SIGINT, oldintr);
  473.     mflag = 0;
  474. }
  475.  
  476. reget(argc, argv)
  477.     char *argv[];
  478. {
  479.     (void) getit(argc, argv, 1, "r+w");
  480. }
  481.  
  482. get(argc, argv)
  483.     char *argv[];
  484. {
  485.     (void) getit(argc, argv, 0, restart_point ? "r+w" : "w" );
  486. }
  487.  
  488. /*
  489.  * Receive one file.
  490.  */
  491. getit(argc, argv, restartit, mode)
  492.     char *argv[];
  493.     char *mode;
  494. {
  495.     int loc = 0;
  496.     char *oldargv1, *oldargv2;
  497.  
  498.     if (argc == 2) {
  499.         argc++;
  500.         argv[2] = argv[1];
  501.         loc++;
  502.     }
  503.     if (argc < 2) {
  504.         (void) strcat(line, " ");
  505.         printf("(remote-file) ");
  506.         (void) gets(&line[strlen(line)]);
  507.         makeargv();
  508.         argc = margc;
  509.         argv = margv;
  510.     }
  511.     if (argc < 2) {
  512. usage:
  513.         printf("usage: %s remote-file [ local-file ]\n", argv[0]);
  514.         code = -1;
  515.         return (0);
  516.     }
  517.     if (argc < 3) {
  518.         (void) strcat(line, " ");
  519.         printf("(local-file) ");
  520.         (void) gets(&line[strlen(line)]);
  521.         makeargv();
  522.         argc = margc;
  523.         argv = margv;
  524.     }
  525.     if (argc < 3) 
  526.         goto usage;
  527.     oldargv1 = argv[1];
  528.     oldargv2 = argv[2];
  529.     if (!globulize(&argv[2])) {
  530.         code = -1;
  531.         return (0);
  532.     }
  533.     if (loc && mcase) {
  534.         char *tp = argv[1], *tp2, tmpbuf[MAXPATHLEN];
  535.  
  536.         while (*tp && !islower(*tp)) {
  537.             tp++;
  538.         }
  539.         if (!*tp) {
  540.             tp = argv[2];
  541.             tp2 = tmpbuf;
  542.             while ((*tp2 = *tp) != NULL) {
  543.                 if (isupper(*tp2)) {
  544.                     *tp2 = 'a' + *tp2 - 'A';
  545.                 }
  546.                 tp++;
  547.                 tp2++;
  548.             }
  549.             argv[2] = tmpbuf;
  550.         }
  551.     }
  552.     if (loc && ntflag)
  553.         argv[2] = dotrans(argv[2]);
  554.     if (loc && mapflag)
  555.         argv[2] = domap(argv[2]);
  556.     if (restartit) {
  557.         struct stat stbuf;
  558.         int ret;
  559.  
  560.         ret = stat(argv[2], &stbuf);
  561.         if (restartit == 1) {
  562.             if (ret < 0) {
  563.                 perror(argv[2]);
  564.                 return (0);
  565.             }
  566.             restart_point = stbuf.st_size;
  567.         } else {
  568.             if (ret == 0) {
  569.                 int overbose;
  570.  
  571.                 overbose = verbose;
  572.                 if (debug == 0)
  573.                     verbose = -1;
  574.                 if (command("MDTM %s", argv[1]) == COMPLETE) {
  575.                     int yy, mo, day, hour, min, sec;
  576.                     struct tm *tm;
  577.                     verbose = overbose;
  578.                     sscanf(reply_string,
  579.                         "%*s %04d%02d%02d%02d%02d%02d",
  580.                         &yy, &mo, &day, &hour, &min, &sec);
  581.                     tm = gmtime(&stbuf.st_mtime);
  582.                     tm->tm_mon++;
  583.                     if (tm->tm_year > yy%100)
  584.                         return (1);
  585.                     else if (tm->tm_year == yy%100) {
  586.                         if (tm->tm_mon > mo)
  587.                             return (1);
  588.                     } else if (tm->tm_mon == mo) {
  589.                         if (tm->tm_mday > day)
  590.                             return (1);
  591.                     } else if (tm->tm_mday == day) {
  592.                         if (tm->tm_hour > hour)
  593.                             return (1);
  594.                     } else if (tm->tm_hour == hour) {
  595.                         if (tm->tm_min > min)
  596.                             return (1);
  597.                     } else if (tm->tm_min == min) {
  598.                         if (tm->tm_sec > sec)
  599.                             return (1);
  600.                     }
  601.                 } else {
  602.                     fputs(reply_string, stdout);
  603.                     verbose = overbose;
  604.                     return (0);
  605.                 }
  606.             }
  607.         }
  608.     }
  609.  
  610.     recvrequest("RETR", argv[2], argv[1], mode,
  611.         argv[1] != oldargv1 || argv[2] != oldargv2);
  612.     restart_point = 0;
  613.     return (0);
  614. }
  615.  
  616. mabort()
  617. {
  618.     int ointer;
  619.     extern jmp_buf jabort;
  620.  
  621.     printf("\n");
  622.     (void) fflush(stdout);
  623.     if (mflag && fromatty) {
  624.         ointer = interactive;
  625.         interactive = 1;
  626.         if (confirm("Continue with", mname)) {
  627.             interactive = ointer;
  628.             longjmp(jabort,0);
  629.         }
  630.         interactive = ointer;
  631.     }
  632.     mflag = 0;
  633.     longjmp(jabort,0);
  634. }
  635.  
  636. /*
  637.  * Get multiple files.
  638.  */
  639. mget(argc, argv)
  640.     char *argv[];
  641. {
  642.     char *cp, *tp, *tp2, tmpbuf[MAXPATHLEN];
  643.     int ointer, (*oldintr)(), mabort();
  644.     extern jmp_buf jabort;
  645.  
  646.     if (argc < 2) {
  647.         (void) strcat(line, " ");
  648.         printf("(remote-files) ");
  649.         (void) gets(&line[strlen(line)]);
  650.         makeargv();
  651.         argc = margc;
  652.         argv = margv;
  653.     }
  654.     if (argc < 2) {
  655.         printf("usage:%s remote-files\n", argv[0]);
  656.         code = -1;
  657.         return;
  658.     }
  659.     mname = argv[0];
  660.     mflag = 1;
  661.     oldintr = signal(SIGINT,mabort);
  662.     (void) setjmp(jabort);
  663.     while ((cp = remglob(argv,proxy)) != NULL) {
  664.         if (*cp == '\0') {
  665.             mflag = 0;
  666.             continue;
  667.         }
  668.         if (mflag && confirm(argv[0], cp)) {
  669.             tp = cp;
  670.             if (mcase) {
  671.                 while (*tp && !islower(*tp)) {
  672.                     tp++;
  673.                 }
  674.                 if (!*tp) {
  675.                     tp = cp;
  676.                     tp2 = tmpbuf;
  677.                     while ((*tp2 = *tp) != NULL) {
  678.                         if (isupper(*tp2)) {
  679.                             *tp2 = 'a' + *tp2 - 'A';
  680.                         }
  681.                         tp++;
  682.                         tp2++;
  683.                     }
  684.                 }
  685.                 tp = tmpbuf;
  686.             }
  687.             if (ntflag) {
  688.                 tp = dotrans(tp);
  689.             }
  690.             if (mapflag) {
  691.                 tp = domap(tp);
  692.             }
  693.             recvrequest("RETR", tp, cp, "w",
  694.                 tp != cp || !interactive);
  695.             if (!mflag && fromatty) {
  696.                 ointer = interactive;
  697.                 interactive = 1;
  698.                 if (confirm("Continue with","mget")) {
  699.                     mflag++;
  700.                 }
  701.                 interactive = ointer;
  702.             }
  703.         }
  704.     }
  705.     (void) signal(SIGINT,oldintr);
  706.     mflag = 0;
  707. }
  708.  
  709. char *
  710. remglob(argv,doswitch)
  711.     char *argv[];
  712.     int doswitch;
  713. {
  714.     char temp[16];
  715.     static char buf[MAXPATHLEN];
  716.     static FILE *ftemp = NULL;
  717.     static char **args;
  718.     int oldverbose, oldhash;
  719.     char *cp, *mode;
  720.  
  721.     if (!mflag) {
  722.         if (!doglob) {
  723.             args = NULL;
  724.         }
  725.         else {
  726.             if (ftemp) {
  727.                 (void) fclose(ftemp);
  728.                 ftemp = NULL;
  729.             }
  730.         }
  731.         return(NULL);
  732.     }
  733.     if (!doglob) {
  734.         if (args == NULL)
  735.             args = argv;
  736.         if ((cp = *++args) == NULL)
  737.             args = NULL;
  738.         return (cp);
  739.     }
  740.     if (ftemp == NULL) {
  741.         (void) strcpy(temp, "/tmp/ftpXXXXXX");
  742.         (void) mktemp(temp);
  743.         oldverbose = verbose, verbose = 0;
  744.         oldhash = hash, hash = 0;
  745.         if (doswitch) {
  746.             pswitch(!proxy);
  747.         }
  748.         for (mode = "w"; *++argv != NULL; mode = "a")
  749.             recvrequest ("NLST", temp, *argv, mode, 0);
  750.         if (doswitch) {
  751.             pswitch(!proxy);
  752.         }
  753.         verbose = oldverbose; hash = oldhash;
  754.         ftemp = fopen(temp, "r");
  755.         (void) unlink(temp);
  756.         if (ftemp == NULL) {
  757.             printf("can't find list of remote files, oops\n");
  758.             return (NULL);
  759.         }
  760.     }
  761.     if (fgets(buf, sizeof (buf), ftemp) == NULL) {
  762.         (void) fclose(ftemp), ftemp = NULL;
  763.         return (NULL);
  764.     }
  765.     if ((cp = index(buf, '\n')) != NULL)
  766.         *cp = '\0';
  767.     return (buf);
  768. }
  769.  
  770. char *
  771. onoff(bool)
  772.     int bool;
  773. {
  774.  
  775.     return (bool ? "on" : "off");
  776. }
  777.  
  778. /*
  779.  * Show status.
  780.  */
  781. /*ARGSUSED*/
  782. status(argc, argv)
  783.     char *argv[];
  784. {
  785.     int i;
  786.  
  787.     if (connected)
  788.         printf("Connected to %s.\n", hostname);
  789.     else
  790.         printf("Not connected.\n");
  791.     if (!proxy) {
  792.         pswitch(1);
  793.         if (connected) {
  794.             printf("Connected for proxy commands to %s.\n", hostname);
  795.         }
  796.         else {
  797.             printf("No proxy connection.\n");
  798.         }
  799.         pswitch(0);
  800.     }
  801.     printf("Mode: %s; Type: %s; Form: %s; Structure: %s\n",
  802.         modename, typename, formname, structname);
  803.     printf("Verbose: %s; Bell: %s; Prompting: %s; Globbing: %s\n", 
  804.         onoff(verbose), onoff(bell), onoff(interactive),
  805.         onoff(doglob));
  806.     printf("Store unique: %s; Receive unique: %s\n", onoff(sunique),
  807.         onoff(runique));
  808.     printf("Case: %s; CR stripping: %s\n",onoff(mcase),onoff(crflag));
  809.     if (ntflag) {
  810.         printf("Ntrans: (in) %s (out) %s\n", ntin,ntout);
  811.     }
  812.     else {
  813.         printf("Ntrans: off\n");
  814.     }
  815.     if (mapflag) {
  816.         printf("Nmap: (in) %s (out) %s\n", mapin, mapout);
  817.     }
  818.     else {
  819.         printf("Nmap: off\n");
  820.     }
  821.     printf("Hash mark printing: %s; Use of PORT cmds: %s\n",
  822.         onoff(hash), onoff(sendport));
  823.     if (macnum > 0) {
  824.         printf("Macros:\n");
  825.         for (i=0; i<macnum; i++) {
  826.             printf("\t%s\n",macros[i].mac_name);
  827.         }
  828.     }
  829.     code = 0;
  830. }
  831.  
  832. /*
  833.  * Set beep on cmd completed mode.
  834.  */
  835. /*VARARGS*/
  836. setbell()
  837. {
  838.  
  839.     bell = !bell;
  840.     printf("Bell mode %s.\n", onoff(bell));
  841.     code = bell;
  842. }
  843.  
  844. /*
  845.  * Turn on packet tracing.
  846.  */
  847. /*VARARGS*/
  848. settrace()
  849. {
  850.  
  851.     trace = !trace;
  852.     printf("Packet tracing %s.\n", onoff(trace));
  853.     code = trace;
  854. }
  855.  
  856. /*
  857.  * Toggle hash mark printing during transfers.
  858.  */
  859. /*VARARGS*/
  860. sethash()
  861. {
  862.  
  863.     hash = !hash;
  864.     printf("Hash mark printing %s", onoff(hash));
  865.     code = hash;
  866.     if (hash)
  867.         printf(" (%d bytes/hash mark)", 1024);
  868.     printf(".\n");
  869. }
  870.  
  871. /*
  872.  * Turn on printing of server echo's.
  873.  */
  874. /*VARARGS*/
  875. setverbose()
  876. {
  877.  
  878.     verbose = !verbose;
  879.     printf("Verbose mode %s.\n", onoff(verbose));
  880.     code = verbose;
  881. }
  882.  
  883. /*
  884.  * Toggle PORT cmd use before each data connection.
  885.  */
  886. /*VARARGS*/
  887. setport()
  888. {
  889.  
  890.     sendport = !sendport;
  891.     printf("Use of PORT cmds %s.\n", onoff(sendport));
  892.     code = sendport;
  893. }
  894.  
  895. /*
  896.  * Turn on interactive prompting
  897.  * during mget, mput, and mdelete.
  898.  */
  899. /*VARARGS*/
  900. setprompt()
  901. {
  902.  
  903.     interactive = !interactive;
  904.     printf("Interactive mode %s.\n", onoff(interactive));
  905.     code = interactive;
  906. }
  907.  
  908. /*
  909.  * Toggle metacharacter interpretation
  910.  * on local file names.
  911.  */
  912. /*VARARGS*/
  913. setglob()
  914. {
  915.     
  916.     doglob = !doglob;
  917.     printf("Globbing %s.\n", onoff(doglob));
  918.     code = doglob;
  919. }
  920.  
  921. /*
  922.  * Set debugging mode on/off and/or
  923.  * set level of debugging.
  924.  */
  925. /*VARARGS*/
  926. setdebug(argc, argv)
  927.     char *argv[];
  928. {
  929.     int val;
  930.  
  931.     if (argc > 1) {
  932.         val = atoi(argv[1]);
  933.         if (val < 0) {
  934.             printf("%s: bad debugging value.\n", argv[1]);
  935.             code = -1;
  936.             return;
  937.         }
  938.     } else
  939.         val = !debug;
  940.     debug = val;
  941.     if (debug)
  942.         options |= SO_DEBUG;
  943.     else
  944.         options &= ~SO_DEBUG;
  945.     printf("Debugging %s (debug=%d).\n", onoff(debug), debug);
  946.     code = debug > 0;
  947. }
  948.  
  949. /*
  950.  * Set current working directory
  951.  * on remote machine.
  952.  */
  953. cd(argc, argv)
  954.     char *argv[];
  955. {
  956.  
  957.     if (argc < 2) {
  958.         (void) strcat(line, " ");
  959.         printf("(remote-directory) ");
  960.         (void) gets(&line[strlen(line)]);
  961.         makeargv();
  962.         argc = margc;
  963.         argv = margv;
  964.     }
  965.     if (argc < 2) {
  966.         printf("usage:%s remote-directory\n", argv[0]);
  967.         code = -1;
  968.         return;
  969.     }
  970.     if (command("CWD %s", argv[1]) == ERROR && code == 500) {
  971.         if (verbose)
  972.             printf("CWD command not recognized, trying XCWD\n");
  973.         (void) command("XCWD %s", argv[1]);
  974.     }
  975. }
  976.  
  977. /*
  978.  * Set current working directory
  979.  * on local machine.
  980.  */
  981. lcd(argc, argv)
  982.     char *argv[];
  983. {
  984.     char buf[MAXPATHLEN];
  985.  
  986.     if (argc < 2)
  987.         argc++, argv[1] = home;
  988.     if (argc != 2) {
  989.         printf("usage:%s local-directory\n", argv[0]);
  990.         code = -1;
  991.         return;
  992.     }
  993.     if (!globulize(&argv[1])) {
  994.         code = -1;
  995.         return;
  996.     }
  997.     if (chdir(argv[1]) < 0) {
  998.         perror(argv[1]);
  999.         code = -1;
  1000.         return;
  1001.     }
  1002.     printf("Local directory now %s\n", getwd(buf));
  1003.     code = 0;
  1004. }
  1005.  
  1006. /*
  1007.  * Delete a single file.
  1008.  */
  1009. delete(argc, argv)
  1010.     char *argv[];
  1011. {
  1012.  
  1013.     if (argc < 2) {
  1014.         (void) strcat(line, " ");
  1015.         printf("(remote-file) ");
  1016.         (void) gets(&line[strlen(line)]);
  1017.         makeargv();
  1018.         argc = margc;
  1019.         argv = margv;
  1020.     }
  1021.     if (argc < 2) {
  1022.         printf("usage:%s remote-file\n", argv[0]);
  1023.         code = -1;
  1024.         return;
  1025.     }
  1026.     (void) command("DELE %s", argv[1]);
  1027. }
  1028.  
  1029. /*
  1030.  * Delete multiple files.
  1031.  */
  1032. mdelete(argc, argv)
  1033.     char *argv[];
  1034. {
  1035.     char *cp;
  1036.     int ointer, (*oldintr)(), mabort();
  1037.     extern jmp_buf jabort;
  1038.  
  1039.     if (argc < 2) {
  1040.         (void) strcat(line, " ");
  1041.         printf("(remote-files) ");
  1042.         (void) gets(&line[strlen(line)]);
  1043.         makeargv();
  1044.         argc = margc;
  1045.         argv = margv;
  1046.     }
  1047.     if (argc < 2) {
  1048.         printf("usage:%s remote-files\n", argv[0]);
  1049.         code = -1;
  1050.         return;
  1051.     }
  1052.     mname = argv[0];
  1053.     mflag = 1;
  1054.     oldintr = signal(SIGINT, mabort);
  1055.     (void) setjmp(jabort);
  1056.     while ((cp = remglob(argv,0)) != NULL) {
  1057.         if (*cp == '\0') {
  1058.             mflag = 0;
  1059.             continue;
  1060.         }
  1061.         if (mflag && confirm(argv[0], cp)) {
  1062.             (void) command("DELE %s", cp);
  1063.             if (!mflag && fromatty) {
  1064.                 ointer = interactive;
  1065.                 interactive = 1;
  1066.                 if (confirm("Continue with", "mdelete")) {
  1067.                     mflag++;
  1068.                 }
  1069.                 interactive = ointer;
  1070.             }
  1071.         }
  1072.     }
  1073.     (void) signal(SIGINT, oldintr);
  1074.     mflag = 0;
  1075. }
  1076.  
  1077. /*
  1078.  * Rename a remote file.
  1079.  */
  1080. renamefile(argc, argv)
  1081.     char *argv[];
  1082. {
  1083.  
  1084.     if (argc < 2) {
  1085.         (void) strcat(line, " ");
  1086.         printf("(from-name) ");
  1087.         (void) gets(&line[strlen(line)]);
  1088.         makeargv();
  1089.         argc = margc;
  1090.         argv = margv;
  1091.     }
  1092.     if (argc < 2) {
  1093. usage:
  1094.         printf("%s from-name to-name\n", argv[0]);
  1095.         code = -1;
  1096.         return;
  1097.     }
  1098.     if (argc < 3) {
  1099.         (void) strcat(line, " ");
  1100.         printf("(to-name) ");
  1101.         (void) gets(&line[strlen(line)]);
  1102.         makeargv();
  1103.         argc = margc;
  1104.         argv = margv;
  1105.     }
  1106.     if (argc < 3) 
  1107.         goto usage;
  1108.     if (command("RNFR %s", argv[1]) == CONTINUE)
  1109.         (void) command("RNTO %s", argv[2]);
  1110. }
  1111.  
  1112. /*
  1113.  * Get a directory listing
  1114.  * of remote files.
  1115.  */
  1116. ls(argc, argv)
  1117.     char *argv[];
  1118. {
  1119.     char *cmd;
  1120.  
  1121.     if (argc < 2)
  1122.         argc++, argv[1] = NULL;
  1123.     if (argc < 3)
  1124.         argc++, argv[2] = "-";
  1125.     if (argc > 3) {
  1126.         printf("usage: %s remote-directory local-file\n", argv[0]);
  1127.         code = -1;
  1128.         return;
  1129.     }
  1130.     cmd = argv[0][0] == 'n' ? "NLST" : "LIST";
  1131.     if (strcmp(argv[2], "-") && !globulize(&argv[2])) {
  1132.         code = -1;
  1133.         return;
  1134.     }
  1135.     if (strcmp(argv[2], "-") && *argv[2] != '|')
  1136.         if (!globulize(&argv[2]) || !confirm("output to local-file:", argv[2])) {
  1137.             code = -1;
  1138.             return;
  1139.     }
  1140.     recvrequest(cmd, argv[2], argv[1], "w", 0);
  1141. }
  1142.  
  1143. /*
  1144.  * Get a directory listing
  1145.  * of multiple remote files.
  1146.  */
  1147. mls(argc, argv)
  1148.     char *argv[];
  1149. {
  1150.     char *cmd, mode[1], *dest;
  1151.     int ointer, i, (*oldintr)(), mabort();
  1152.     extern jmp_buf jabort;
  1153.  
  1154.     if (argc < 2) {
  1155.         (void) strcat(line, " ");
  1156.         printf("(remote-files) ");
  1157.         (void) gets(&line[strlen(line)]);
  1158.         makeargv();
  1159.         argc = margc;
  1160.         argv = margv;
  1161.     }
  1162.     if (argc < 3) {
  1163.         (void) strcat(line, " ");
  1164.         printf("(local-file) ");
  1165.         (void) gets(&line[strlen(line)]);
  1166.         makeargv();
  1167.         argc = margc;
  1168.         argv = margv;
  1169.     }
  1170.     if (argc < 3) {
  1171.         printf("usage:%s remote-files local-file\n", argv[0]);
  1172.         code = -1;
  1173.         return;
  1174.     }
  1175.     dest = argv[argc - 1];
  1176.     argv[argc - 1] = NULL;
  1177.     if (strcmp(dest, "-") && *dest != '|')
  1178.         if (!globulize(&dest) || !confirm("output to local-file:", dest)) {
  1179.             code = -1;
  1180.             return;
  1181.     }
  1182.     cmd = argv[0][1] == 'l' ? "NLST" : "LIST";
  1183.     mname = argv[0];
  1184.     mflag = 1;
  1185.     oldintr = signal(SIGINT, mabort);
  1186.     (void) setjmp(jabort);
  1187.     for (i = 1; mflag && i < argc-1; ++i) {
  1188.         *mode = (i == 1) ? 'w' : 'a';
  1189.         recvrequest(cmd, dest, argv[i], mode, 0);
  1190.         if (!mflag && fromatty) {
  1191.             ointer = interactive;
  1192.             interactive = 1;
  1193.             if (confirm("Continue with", argv[0])) {
  1194.                 mflag ++;
  1195.             }
  1196.             interactive = ointer;
  1197.         }
  1198.     }
  1199.     (void) signal(SIGINT, oldintr);
  1200.     mflag = 0;
  1201. }
  1202.  
  1203. /*
  1204.  * Do a shell escape
  1205.  */
  1206. /*ARGSUSED*/
  1207. shell(argc, argv)
  1208.     char *argv[];
  1209. {
  1210.     int pid, (*old1)(), (*old2)();
  1211.     char shellnam[40], *shell, *namep; 
  1212.     union wait status;
  1213.  
  1214.     old1 = signal (SIGINT, SIG_IGN);
  1215.     old2 = signal (SIGQUIT, SIG_IGN);
  1216.     if ((pid = fork()) == 0) {
  1217.         for (pid = 3; pid < 20; pid++)
  1218.             (void) close(pid);
  1219.         (void) signal(SIGINT, SIG_DFL);
  1220.         (void) signal(SIGQUIT, SIG_DFL);
  1221.         shell = getenv("SHELL");
  1222.         if (shell == NULL)
  1223.             shell = "/bin/sh";
  1224.         namep = rindex(shell,'/');
  1225.         if (namep == NULL)
  1226.             namep = shell;
  1227.         (void) strcpy(shellnam,"-");
  1228.         (void) strcat(shellnam, ++namep);
  1229.         if (strcmp(namep, "sh") != 0)
  1230.             shellnam[0] = '+';
  1231.         if (debug) {
  1232.             printf ("%s\n", shell);
  1233.             (void) fflush (stdout);
  1234.         }
  1235.         if (argc > 1) {
  1236.             execl(shell,shellnam,"-c",altarg,(char *)0);
  1237.         }
  1238.         else {
  1239.             execl(shell,shellnam,(char *)0);
  1240.         }
  1241.         perror(shell);
  1242.         code = -1;
  1243.         exit(1);
  1244.         }
  1245.     if (pid > 0)
  1246.         while (wait(&status) != pid)
  1247.             ;
  1248.     (void) signal(SIGINT, old1);
  1249.     (void) signal(SIGQUIT, old2);
  1250.     if (pid == -1) {
  1251.         perror("Try again later");
  1252.         code = -1;
  1253.     }
  1254.     else {
  1255.         code = 0;
  1256.     }
  1257.     return (0);
  1258. }
  1259.  
  1260. /*
  1261.  * Send new user information (re-login)
  1262.  */
  1263. user(argc, argv)
  1264.     int argc;
  1265.     char **argv;
  1266. {
  1267.     char acct[80], *getpass();
  1268.     int n, aflag = 0;
  1269.  
  1270.     if (argc < 2) {
  1271.         (void) strcat(line, " ");
  1272.         printf("(username) ");
  1273.         (void) gets(&line[strlen(line)]);
  1274.         makeargv();
  1275.         argc = margc;
  1276.         argv = margv;
  1277.     }
  1278.     if (argc > 4) {
  1279.         printf("usage: %s username [password] [account]\n", argv[0]);
  1280.         code = -1;
  1281.         return (0);
  1282.     }
  1283.     n = command("USER %s", argv[1]);
  1284.     if (n == CONTINUE) {
  1285.         if (argc < 3 )
  1286.             argv[2] = getpass("Password: "), argc++;
  1287.         n = command("PASS %s", argv[2]);
  1288.     }
  1289.     if (n == CONTINUE) {
  1290.         if (argc < 4) {
  1291.             printf("Account: "); (void) fflush(stdout);
  1292.             (void) fgets(acct, sizeof(acct) - 1, stdin);
  1293.             acct[strlen(acct) - 1] = '\0';
  1294.             argv[3] = acct; argc++;
  1295.         }
  1296.         n = command("ACCT %s", argv[3]);
  1297.         aflag++;
  1298.     }
  1299.     if (n != COMPLETE) {
  1300.         fprintf(stdout, "Login failed.\n");
  1301.         return (0);
  1302.     }
  1303.     if (!aflag && argc == 4) {
  1304.         (void) command("ACCT %s", argv[3]);
  1305.     }
  1306.     return (1);
  1307. }
  1308.  
  1309. /*
  1310.  * Print working directory.
  1311.  */
  1312. /*VARARGS*/
  1313. pwd()
  1314. {
  1315.     int oldverbose = verbose;
  1316.  
  1317.     /*
  1318.      * If we aren't verbose, this doesn't do anything!
  1319.      */
  1320.     verbose = 1;
  1321.     if (command("PWD") == ERROR && code == 500) {
  1322.         printf("PWD command not recognized, trying XPWD\n");
  1323.         (void) command("XPWD");
  1324.     }
  1325.     verbose = oldverbose;
  1326. }
  1327.  
  1328. /*
  1329.  * Make a directory.
  1330.  */
  1331. makedir(argc, argv)
  1332.     char *argv[];
  1333. {
  1334.  
  1335.     if (argc < 2) {
  1336.         (void) strcat(line, " ");
  1337.         printf("(directory-name) ");
  1338.         (void) gets(&line[strlen(line)]);
  1339.         makeargv();
  1340.         argc = margc;
  1341.         argv = margv;
  1342.     }
  1343.     if (argc < 2) {
  1344.         printf("usage: %s directory-name\n", argv[0]);
  1345.         code = -1;
  1346.         return;
  1347.     }
  1348.     if (command("MKD %s", argv[1]) == ERROR && code == 500) {
  1349.         if (verbose)
  1350.             printf("MKD command not recognized, trying XMKD\n");
  1351.         (void) command("XMKD %s", argv[1]);
  1352.     }
  1353. }
  1354.  
  1355. /*
  1356.  * Remove a directory.
  1357.  */
  1358. removedir(argc, argv)
  1359.     char *argv[];
  1360. {
  1361.  
  1362.     if (argc < 2) {
  1363.         (void) strcat(line, " ");
  1364.         printf("(directory-name) ");
  1365.         (void) gets(&line[strlen(line)]);
  1366.         makeargv();
  1367.         argc = margc;
  1368.         argv = margv;
  1369.     }
  1370.     if (argc < 2) {
  1371.         printf("usage: %s directory-name\n", argv[0]);
  1372.         code = -1;
  1373.         return;
  1374.     }
  1375.     if (command("RMD %s", argv[1]) == ERROR && code == 500) {
  1376.         if (verbose)
  1377.             printf("RMD command not recognized, trying XRMD\n");
  1378.         (void) command("XRMD %s", argv[1]);
  1379.     }
  1380. }
  1381.  
  1382. /*
  1383.  * Send a line, verbatim, to the remote machine.
  1384.  */
  1385. quote(argc, argv)
  1386.     char *argv[];
  1387. {
  1388.     int i;
  1389.     char buf[BUFSIZ];
  1390.  
  1391.     if (argc < 2) {
  1392.         (void) strcat(line, " ");
  1393.         printf("(command line to send) ");
  1394.         (void) gets(&line[strlen(line)]);
  1395.         makeargv();
  1396.         argc = margc;
  1397.         argv = margv;
  1398.     }
  1399.     if (argc < 2) {
  1400.         printf("usage: %s line-to-send\n", argv[0]);
  1401.         code = -1;
  1402.         return;
  1403.     }
  1404.     (void) strcpy(buf, argv[1]);
  1405.     for (i = 2; i < argc; i++) {
  1406.         (void) strcat(buf, " ");
  1407.         (void) strcat(buf, argv[i]);
  1408.     }
  1409.     if (command(buf) == PRELIM) {
  1410.         while (getreply(0) == PRELIM);
  1411.     }
  1412. }
  1413.  
  1414. /*
  1415.  * Send a SITE command to the remote machine.  The line
  1416.  * is sent almost verbatim to the remote machine, the
  1417.  * first argument is changed to SITE.
  1418.  */
  1419.  
  1420. site(argc, argv)
  1421.     char *argv[];
  1422. {
  1423.     int i;
  1424.     char buf[BUFSIZ];
  1425.  
  1426.     if (argc < 2) {
  1427.         (void) strcat(line, " ");
  1428.         printf("(arguments to SITE command) ");
  1429.         (void) gets(&line[strlen(line)]);
  1430.         makeargv();
  1431.         argc = margc;
  1432.         argv = margv;
  1433.     }
  1434.     if (argc < 2) {
  1435.         printf("usage: %s line-to-send\n", argv[0]);
  1436.         code = -1;
  1437.         return;
  1438.     }
  1439.     (void) strcpy(buf, "SITE ");
  1440.     (void) strcat(buf, argv[1]);
  1441.     for (i = 2; i < argc; i++) {
  1442.         (void) strcat(buf, " ");
  1443.         (void) strcat(buf, argv[i]);
  1444.     }
  1445.     if (command(buf) == PRELIM) {
  1446.         while (getreply(0) == PRELIM);
  1447.     }
  1448. }
  1449.  
  1450. do_chmod(argc, argv)
  1451.     char *argv[];
  1452. {
  1453.     if (argc == 2) {
  1454.         printf("usage: %s mode file-name\n", argv[0]);
  1455.         code = -1;
  1456.         return;
  1457.     }
  1458.     if (argc < 3) {
  1459.         (void) strcat(line, " ");
  1460.         printf("(mode and file-name) ");
  1461.         (void) gets(&line[strlen(line)]);
  1462.         makeargv();
  1463.         argc = margc;
  1464.         argv = margv;
  1465.     }
  1466.     if (argc != 3) {
  1467.         printf("usage: %s mode file-name\n", argv[0]);
  1468.         code = -1;
  1469.         return;
  1470.     }
  1471.     (void)command("SITE CHMOD %s %s", argv[1], argv[2]);
  1472. }
  1473.  
  1474. do_umask(argc, argv)
  1475.     char *argv[];
  1476. {
  1477.     int oldverbose = verbose;
  1478.  
  1479.     verbose = 1;
  1480.     (void) command(argc == 1 ? "SITE UMASK" : "SITE UMASK %s", argv[1]);
  1481.     verbose = oldverbose;
  1482. }
  1483.  
  1484. idle(argc, argv)
  1485.     char *argv[];
  1486. {
  1487.     int oldverbose = verbose;
  1488.  
  1489.     verbose = 1;
  1490.     (void) command(argc == 1 ? "SITE IDLE" : "SITE IDLE %s", argv[1]);
  1491.     verbose = oldverbose;
  1492. }
  1493.  
  1494. /*
  1495.  * Ask the other side for help.
  1496.  */
  1497. rmthelp(argc, argv)
  1498.     char *argv[];
  1499. {
  1500.     int oldverbose = verbose;
  1501.  
  1502.     verbose = 1;
  1503.     (void) command(argc == 1 ? "HELP" : "HELP %s", argv[1]);
  1504.     verbose = oldverbose;
  1505. }
  1506.  
  1507. /*
  1508.  * Terminate session and exit.
  1509.  */
  1510. /*VARARGS*/
  1511. quit()
  1512. {
  1513.  
  1514.     if (connected)
  1515.         disconnect();
  1516.     pswitch(1);
  1517.     if (connected) {
  1518.         disconnect();
  1519.     }
  1520.     exit(0);
  1521. }
  1522.  
  1523. /*
  1524.  * Terminate session, but don't exit.
  1525.  */
  1526. disconnect()
  1527. {
  1528.     extern FILE *cout;
  1529.     extern int data;
  1530.  
  1531.     if (!connected)
  1532.         return;
  1533.     (void) command("QUIT");
  1534.     if (cout) {
  1535.         (void) fclose(cout);
  1536.     }
  1537.     cout = NULL;
  1538.     connected = 0;
  1539.     data = -1;
  1540.     if (!proxy) {
  1541.         macnum = 0;
  1542.     }
  1543. }
  1544.  
  1545. confirm(cmd, file)
  1546.     char *cmd, *file;
  1547. {
  1548.     char line[BUFSIZ];
  1549.  
  1550.     if (!interactive)
  1551.         return (1);
  1552.     printf("%s %s? ", cmd, file);
  1553.     (void) fflush(stdout);
  1554.     (void) gets(line);
  1555.     return (*line != 'n' && *line != 'N');
  1556. }
  1557.  
  1558. fatal(msg)
  1559.     char *msg;
  1560. {
  1561.  
  1562.     fprintf(stderr, "ftp: %s\n", msg);
  1563.     exit(1);
  1564. }
  1565.  
  1566. /*
  1567.  * Glob a local file name specification with
  1568.  * the expectation of a single return value.
  1569.  * Can't control multiple values being expanded
  1570.  * from the expression, we return only the first.
  1571.  */
  1572. globulize(cpp)
  1573.     char **cpp;
  1574. {
  1575.     char **globbed;
  1576.  
  1577.     if (!doglob)
  1578.         return (1);
  1579.     globbed = glob(*cpp);
  1580.     if (globerr != NULL) {
  1581.         printf("%s: %s\n", *cpp, globerr);
  1582.         if (globbed) {
  1583.             blkfree(globbed);
  1584.             free(globbed);
  1585.         }
  1586.         return (0);
  1587.     }
  1588.     if (globbed) {
  1589.         *cpp = *globbed++;
  1590.         /* don't waste too much memory */
  1591.         if (*globbed) {
  1592.             blkfree(globbed);
  1593.             free(globbed);
  1594.         }
  1595.     }
  1596.     return (1);
  1597. }
  1598.  
  1599. account(argc,argv)
  1600.     int argc;
  1601.     char **argv;
  1602. {
  1603.     char acct[50], *getpass(), *ap;
  1604.  
  1605.     if (argc > 1) {
  1606.         ++argv;
  1607.         --argc;
  1608.         (void) strncpy(acct,*argv,49);
  1609.         acct[49] = '\0';
  1610.         while (argc > 1) {
  1611.             --argc;
  1612.             ++argv;
  1613.             (void) strncat(acct,*argv, 49-strlen(acct));
  1614.         }
  1615.         ap = acct;
  1616.     }
  1617.     else {
  1618.         ap = getpass("Account:");
  1619.     }
  1620.     (void) command("ACCT %s", ap);
  1621. }
  1622.  
  1623. jmp_buf abortprox;
  1624.  
  1625. proxabort()
  1626. {
  1627.     extern int proxy;
  1628.  
  1629.     if (!proxy) {
  1630.         pswitch(1);
  1631.     }
  1632.     if (connected) {
  1633.         proxflag = 1;
  1634.     }
  1635.     else {
  1636.         proxflag = 0;
  1637.     }
  1638.     pswitch(0);
  1639.     longjmp(abortprox,1);
  1640. }
  1641.  
  1642. doproxy(argc,argv)
  1643.     int argc;
  1644.     char *argv[];
  1645. {
  1646.     int (*oldintr)(), proxabort();
  1647.     register struct cmd *c;
  1648.     struct cmd *getcmd();
  1649.     extern struct cmd cmdtab[];
  1650.     extern jmp_buf abortprox;
  1651.  
  1652.     if (argc < 2) {
  1653.         (void) strcat(line, " ");
  1654.         printf("(command) ");
  1655.         (void) gets(&line[strlen(line)]);
  1656.         makeargv();
  1657.         argc = margc;
  1658.         argv = margv;
  1659.     }
  1660.     if (argc < 2) {
  1661.         printf("usage:%s command\n", argv[0]);
  1662.         code = -1;
  1663.         return;
  1664.     }
  1665.     c = getcmd(argv[1]);
  1666.     if (c == (struct cmd *) -1) {
  1667.         printf("?Ambiguous command\n");
  1668.         (void) fflush(stdout);
  1669.         code = -1;
  1670.         return;
  1671.     }
  1672.     if (c == 0) {
  1673.         printf("?Invalid command\n");
  1674.         (void) fflush(stdout);
  1675.         code = -1;
  1676.         return;
  1677.     }
  1678.     if (!c->c_proxy) {
  1679.         printf("?Invalid proxy command\n");
  1680.         (void) fflush(stdout);
  1681.         code = -1;
  1682.         return;
  1683.     }
  1684.     if (setjmp(abortprox)) {
  1685.         code = -1;
  1686.         return;
  1687.     }
  1688.     oldintr = signal(SIGINT, proxabort);
  1689.     pswitch(1);
  1690.     if (c->c_conn && !connected) {
  1691.         printf("Not connected\n");
  1692.         (void) fflush(stdout);
  1693.         pswitch(0);
  1694.         (void) signal(SIGINT, oldintr);
  1695.         code = -1;
  1696.         return;
  1697.     }
  1698.     (*c->c_handler)(argc-1, argv+1);
  1699.     if (connected) {
  1700.         proxflag = 1;
  1701.     }
  1702.     else {
  1703.         proxflag = 0;
  1704.     }
  1705.     pswitch(0);
  1706.     (void) signal(SIGINT, oldintr);
  1707. }
  1708.  
  1709. setcase()
  1710. {
  1711.     mcase = !mcase;
  1712.     printf("Case mapping %s.\n", onoff(mcase));
  1713.     code = mcase;
  1714. }
  1715.  
  1716. setcr()
  1717. {
  1718.     crflag = !crflag;
  1719.     printf("Carriage Return stripping %s.\n", onoff(crflag));
  1720.     code = crflag;
  1721. }
  1722.  
  1723. setntrans(argc,argv)
  1724.     int argc;
  1725.     char *argv[];
  1726. {
  1727.     if (argc == 1) {
  1728.         ntflag = 0;
  1729.         printf("Ntrans off.\n");
  1730.         code = ntflag;
  1731.         return;
  1732.     }
  1733.     ntflag++;
  1734.     code = ntflag;
  1735.     (void) strncpy(ntin, argv[1], 16);
  1736.     ntin[16] = '\0';
  1737.     if (argc == 2) {
  1738.         ntout[0] = '\0';
  1739.         return;
  1740.     }
  1741.     (void) strncpy(ntout, argv[2], 16);
  1742.     ntout[16] = '\0';
  1743. }
  1744.  
  1745. char *
  1746. dotrans(name)
  1747.     char *name;
  1748. {
  1749.     static char new[MAXPATHLEN];
  1750.     char *cp1, *cp2 = new;
  1751.     register int i, ostop, found;
  1752.  
  1753.     for (ostop = 0; *(ntout + ostop) && ostop < 16; ostop++);
  1754.     for (cp1 = name; *cp1; cp1++) {
  1755.         found = 0;
  1756.         for (i = 0; *(ntin + i) && i < 16; i++) {
  1757.             if (*cp1 == *(ntin + i)) {
  1758.                 found++;
  1759.                 if (i < ostop) {
  1760.                     *cp2++ = *(ntout + i);
  1761.                 }
  1762.                 break;
  1763.             }
  1764.         }
  1765.         if (!found) {
  1766.             *cp2++ = *cp1;
  1767.         }
  1768.     }
  1769.     *cp2 = '\0';
  1770.     return(new);
  1771. }
  1772.  
  1773. setnmap(argc, argv)
  1774.     int argc;
  1775.     char *argv[];
  1776. {
  1777.     char *cp;
  1778.  
  1779.     if (argc == 1) {
  1780.         mapflag = 0;
  1781.         printf("Nmap off.\n");
  1782.         code = mapflag;
  1783.         return;
  1784.     }
  1785.     if (argc < 3) {
  1786.         (void) strcat(line, " ");
  1787.         printf("(mapout) ");
  1788.         (void) gets(&line[strlen(line)]);
  1789.         makeargv();
  1790.         argc = margc;
  1791.         argv = margv;
  1792.     }
  1793.     if (argc < 3) {
  1794.         printf("Usage: %s [mapin mapout]\n",argv[0]);
  1795.         code = -1;
  1796.         return;
  1797.     }
  1798.     mapflag = 1;
  1799.     code = 1;
  1800.     cp = index(altarg, ' ');
  1801.     if (proxy) {
  1802.         while(*++cp == ' ');
  1803.         altarg = cp;
  1804.         cp = index(altarg, ' ');
  1805.     }
  1806.     *cp = '\0';
  1807.     (void) strncpy(mapin, altarg, MAXPATHLEN - 1);
  1808.     while (*++cp == ' ');
  1809.     (void) strncpy(mapout, cp, MAXPATHLEN - 1);
  1810. }
  1811.  
  1812. char *
  1813. domap(name)
  1814.     char *name;
  1815. {
  1816.     static char new[MAXPATHLEN];
  1817.     register char *cp1 = name, *cp2 = mapin;
  1818.     char *tp[9], *te[9];
  1819.     int i, toks[9], toknum = 0, match = 1;
  1820.  
  1821.     for (i=0; i < 9; ++i) {
  1822.         toks[i] = 0;
  1823.     }
  1824.     while (match && *cp1 && *cp2) {
  1825.         switch (*cp2) {
  1826.             case '\\':
  1827.                 if (*++cp2 != *cp1) {
  1828.                     match = 0;
  1829.                 }
  1830.                 break;
  1831.             case '$':
  1832.                 if (*(cp2+1) >= '1' && (*cp2+1) <= '9') {
  1833.                     if (*cp1 != *(++cp2+1)) {
  1834.                         toks[toknum = *cp2 - '1']++;
  1835.                         tp[toknum] = cp1;
  1836.                         while (*++cp1 && *(cp2+1)
  1837.                             != *cp1);
  1838.                         te[toknum] = cp1;
  1839.                     }
  1840.                     cp2++;
  1841.                     break;
  1842.                 }
  1843.                 /* FALLTHROUGH */
  1844.             default:
  1845.                 if (*cp2 != *cp1) {
  1846.                     match = 0;
  1847.                 }
  1848.                 break;
  1849.         }
  1850.         if (match && *cp1) {
  1851.             cp1++;
  1852.         }
  1853.         if (match && *cp2) {
  1854.             cp2++;
  1855.         }
  1856.     }
  1857.     if (!match && *cp1) /* last token mismatch */
  1858.     {
  1859.         toks[toknum] = 0;
  1860.     }
  1861.     cp1 = new;
  1862.     *cp1 = '\0';
  1863.     cp2 = mapout;
  1864.     while (*cp2) {
  1865.         match = 0;
  1866.         switch (*cp2) {
  1867.             case '\\':
  1868.                 if (*(cp2 + 1)) {
  1869.                     *cp1++ = *++cp2;
  1870.                 }
  1871.                 break;
  1872.             case '[':
  1873. LOOP:
  1874.                 if (*++cp2 == '$' && isdigit(*(cp2+1))) { 
  1875.                     if (*++cp2 == '0') {
  1876.                         char *cp3 = name;
  1877.  
  1878.                         while (*cp3) {
  1879.                             *cp1++ = *cp3++;
  1880.                         }
  1881.                         match = 1;
  1882.                     }
  1883.                     else if (toks[toknum = *cp2 - '1']) {
  1884.                         char *cp3 = tp[toknum];
  1885.  
  1886.                         while (cp3 != te[toknum]) {
  1887.                             *cp1++ = *cp3++;
  1888.                         }
  1889.                         match = 1;
  1890.                     }
  1891.                 }
  1892.                 else {
  1893.                     while (*cp2 && *cp2 != ',' && 
  1894.                         *cp2 != ']') {
  1895.                         if (*cp2 == '\\') {
  1896.                             cp2++;
  1897.                         }
  1898.                         else if (*cp2 == '$' &&
  1899.                                    isdigit(*(cp2+1))) {
  1900.                             if (*++cp2 == '0') {
  1901.                                char *cp3 = name;
  1902.  
  1903.                                while (*cp3) {
  1904.                                 *cp1++ = *cp3++;
  1905.                                }
  1906.                             }
  1907.                             else if (toks[toknum =
  1908.                                 *cp2 - '1']) {
  1909.                                char *cp3=tp[toknum];
  1910.  
  1911.                                while (cp3 !=
  1912.                                   te[toknum]) {
  1913.                                 *cp1++ = *cp3++;
  1914.                                }
  1915.                             }
  1916.                         }
  1917.                         else if (*cp2) {
  1918.                             *cp1++ = *cp2++;
  1919.                         }
  1920.                     }
  1921.                     if (!*cp2) {
  1922.                         printf("nmap: unbalanced brackets\n");
  1923.                         return(name);
  1924.                     }
  1925.                     match = 1;
  1926.                     cp2--;
  1927.                 }
  1928.                 if (match) {
  1929.                     while (*++cp2 && *cp2 != ']') {
  1930.                           if (*cp2 == '\\' && *(cp2 + 1)) {
  1931.                             cp2++;
  1932.                           }
  1933.                     }
  1934.                     if (!*cp2) {
  1935.                         printf("nmap: unbalanced brackets\n");
  1936.                         return(name);
  1937.                     }
  1938.                     break;
  1939.                 }
  1940.                 switch (*++cp2) {
  1941.                     case ',':
  1942.                         goto LOOP;
  1943.                     case ']':
  1944.                         break;
  1945.                     default:
  1946.                         cp2--;
  1947.                         goto LOOP;
  1948.                 }
  1949.                 break;
  1950.             case '$':
  1951.                 if (isdigit(*(cp2 + 1))) {
  1952.                     if (*++cp2 == '0') {
  1953.                         char *cp3 = name;
  1954.  
  1955.                         while (*cp3) {
  1956.                             *cp1++ = *cp3++;
  1957.                         }
  1958.                     }
  1959.                     else if (toks[toknum = *cp2 - '1']) {
  1960.                         char *cp3 = tp[toknum];
  1961.  
  1962.                         while (cp3 != te[toknum]) {
  1963.                             *cp1++ = *cp3++;
  1964.                         }
  1965.                     }
  1966.                     break;
  1967.                 }
  1968.                 /* intentional drop through */
  1969.             default:
  1970.                 *cp1++ = *cp2;
  1971.                 break;
  1972.         }
  1973.         cp2++;
  1974.     }
  1975.     *cp1 = '\0';
  1976.     if (!*new) {
  1977.         return(name);
  1978.     }
  1979.     return(new);
  1980. }
  1981.  
  1982. setsunique()
  1983. {
  1984.     sunique = !sunique;
  1985.     printf("Store unique %s.\n", onoff(sunique));
  1986.     code = sunique;
  1987. }
  1988.  
  1989. setrunique()
  1990. {
  1991.     runique = !runique;
  1992.     printf("Receive unique %s.\n", onoff(runique));
  1993.     code = runique;
  1994. }
  1995.  
  1996. /* change directory to perent directory */
  1997. cdup()
  1998. {
  1999.     if (command("CDUP") == ERROR && code == 500) {
  2000.         if (verbose)
  2001.             printf("CDUP command not recognized, trying XCUP\n");
  2002.         (void) command("XCUP");
  2003.     }
  2004. }
  2005.  
  2006. /* restart transfer at specific point */
  2007. restart(argc, argv)
  2008.     int argc;
  2009.     char *argv[];
  2010. {
  2011.     extern long atol();
  2012.     if (argc != 2)
  2013.         printf("restart: offset not specified\n");
  2014.     else {
  2015.         restart_point = atol(argv[1]);
  2016.         printf("restarting at %ld. %s\n", restart_point,
  2017.             "execute get, put or append to initiate transfer");
  2018.     }
  2019. }
  2020.  
  2021. /* show remote system type */
  2022. syst()
  2023. {
  2024.     (void) command("SYST");
  2025. }
  2026.  
  2027. macdef(argc, argv)
  2028.     int argc;
  2029.     char *argv[];
  2030. {
  2031.     char *tmp;
  2032.     int c;
  2033.  
  2034.     if (macnum == 16) {
  2035.         printf("Limit of 16 macros have already been defined\n");
  2036.         code = -1;
  2037.         return;
  2038.     }
  2039.     if (argc < 2) {
  2040.         (void) strcat(line, " ");
  2041.         printf("(macro name) ");
  2042.         (void) gets(&line[strlen(line)]);
  2043.         makeargv();
  2044.         argc = margc;
  2045.         argv = margv;
  2046.     }
  2047.     if (argc != 2) {
  2048.         printf("Usage: %s macro_name\n",argv[0]);
  2049.         code = -1;
  2050.         return;
  2051.     }
  2052.     if (interactive) {
  2053.         printf("Enter macro line by line, terminating it with a null line\n");
  2054.     }
  2055.     (void) strncpy(macros[macnum].mac_name, argv[1], 8);
  2056.     if (macnum == 0) {
  2057.         macros[macnum].mac_start = macbuf;
  2058.     }
  2059.     else {
  2060.         macros[macnum].mac_start = macros[macnum - 1].mac_end + 1;
  2061.     }
  2062.     tmp = macros[macnum].mac_start;
  2063.     while (tmp != macbuf+4096) {
  2064.         if ((c = getchar()) == EOF) {
  2065.             printf("macdef:end of file encountered\n");
  2066.             code = -1;
  2067.             return;
  2068.         }
  2069.         if ((*tmp = c) == '\n') {
  2070.             if (tmp == macros[macnum].mac_start) {
  2071.                 macros[macnum++].mac_end = tmp;
  2072.                 code = 0;
  2073.                 return;
  2074.             }
  2075.             if (*(tmp-1) == '\0') {
  2076.                 macros[macnum++].mac_end = tmp - 1;
  2077.                 code = 0;
  2078.                 return;
  2079.             }
  2080.             *tmp = '\0';
  2081.         }
  2082.         tmp++;
  2083.     }
  2084.     while (1) {
  2085.         while ((c = getchar()) != '\n' && c != EOF)
  2086.             /* LOOP */;
  2087.         if (c == EOF || getchar() == '\n') {
  2088.             printf("Macro not defined - 4k buffer exceeded\n");
  2089.             code = -1;
  2090.             return;
  2091.         }
  2092.     }
  2093. }
  2094.  
  2095. /*
  2096.  * get size of file on remote machine
  2097.  */
  2098. sizecmd(argc, argv)
  2099.     char *argv[];
  2100. {
  2101.  
  2102.     if (argc < 2) {
  2103.         (void) strcat(line, " ");
  2104.         printf("(filename) ");
  2105.         (void) gets(&line[strlen(line)]);
  2106.         makeargv();
  2107.         argc = margc;
  2108.         argv = margv;
  2109.     }
  2110.     if (argc < 2) {
  2111.         printf("usage:%s filename\n", argv[0]);
  2112.         code = -1;
  2113.         return;
  2114.     }
  2115.     (void) command("SIZE %s", argv[1]);
  2116. }
  2117.  
  2118. /*
  2119.  * get last modification time of file on remote machine
  2120.  */
  2121. modtime(argc, argv)
  2122.     char *argv[];
  2123. {
  2124.     int overbose;
  2125.  
  2126.     if (argc < 2) {
  2127.         (void) strcat(line, " ");
  2128.         printf("(filename) ");
  2129.         (void) gets(&line[strlen(line)]);
  2130.         makeargv();
  2131.         argc = margc;
  2132.         argv = margv;
  2133.     }
  2134.     if (argc < 2) {
  2135.         printf("usage:%s filename\n", argv[0]);
  2136.         code = -1;
  2137.         return;
  2138.     }
  2139.     overbose = verbose;
  2140.     if (debug == 0)
  2141.         verbose = -1;
  2142.     if (command("MDTM %s", argv[1]) == COMPLETE) {
  2143.         int yy, mo, day, hour, min, sec;
  2144.         sscanf(reply_string, "%*s %04d%02d%02d%02d%02d%02d", &yy, &mo,
  2145.             &day, &hour, &min, &sec);
  2146.         /* might want to print this in local time */
  2147.         printf("%s\t%02d/%02d/%04d %02d:%02d:%02d GMT\n", argv[1],
  2148.             mo, day, yy, hour, min, sec);
  2149.     } else
  2150.         fputs(reply_string, stdout);
  2151.     verbose = overbose;
  2152. }
  2153.  
  2154. /*
  2155.  * show status on reomte machine
  2156.  */
  2157. rmtstatus(argc, argv)
  2158.     char *argv[];
  2159. {
  2160.     (void) command(argc > 1 ? "STAT %s" : "STAT" , argv[1]);
  2161. }
  2162.  
  2163. /*
  2164.  * get file if modtime is more recent than current file
  2165.  */
  2166. newer(argc, argv)
  2167.     char *argv[];
  2168. {
  2169.     if (getit(argc, argv, -1, "w"))
  2170.         printf("Local file \"%s\" is newer than remote file \"%s\"\n",
  2171.             argv[1], argv[2]);
  2172. }
  2173.